﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;

namespace TodayHumor
{
    public partial class App : Application
    {
        /// <summary>
        /// 전화 응용 프로그램의 루트 프레임에 간단하게 액세스할 수 있습니다.
        /// </summary>
        /// <returns>전화 응용 프로그램의 루트 프레임입니다.</returns>
        public PhoneApplicationFrame RootFrame { get; private set; }

        public new static App Current { get { return (App)Application.Current; } }

        /// <summary>
        /// Application 개체의 생성자입니다.
        /// </summary>
        public App()
        {
            // Catch되지 않은 예외의 전역 처리기입니다. 
            UnhandledException += Application_UnhandledException;

            // 표준 Silverlight 초기화
            InitializeComponent();

            // 전화 관련 초기화
            InitializePhoneApplication();

            // 디버깅하는 동안 그래픽 프로파일링 정보를 표시합니다.
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // 현재 프레임 속도 카운터를 표시합니다.
                Application.Current.Host.Settings.EnableFrameRateCounter = false;

                // 각 프레임에서 다시 그려지는 응용 프로그램의 영역을 표시합니다.
                //Application.Current.Host.Settings.EnableRedrawRegions = true;

                // 색이 지정된 오버레이를 포함하는 GPU에 전달되는 페이지 영역을 표시하는 
                // 비프로덕션 분석 시각화 모드를 설정합니다.
                //Application.Current.Host.Settings.EnableCacheVisualization = true;

                // 응용 프로그램의 PhoneApplicationService 개체에 대한 UserIdleDetectionMode 속성을 사용 안 함으로 설정하여
                // 응용 프로그램 유휴 검색을 해제합니다.
                // 주의:- 디버그 모드에서만 사용합니다. 사용자 유휴 검색을 해제하는 응용 프로그램은 사용자가 전화를 사용하지 않을 경우에도
                // 계속 실행되어 배터리 전원을 소모합니다.
                PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            }

        }

        // CookieContainer : 로그인 정보를 담고 있음
        public static CookieContainer Cookies = new CookieContainer();

        // 로그인 모듈
        public LoginModule LoginModule = new LoginModule();

        // 설정 모듈
        public SettingsModule SettingsModule = new SettingsModule();

        // 열람 기록 로더
        public HistoryLoader HistoryLoader = new HistoryLoader();

        // 에러 발생 시 다음 실행 때 에러 정보를 읽을 파일의 경로
        string ErrorSavePath = "/Error.txt";

        private void Application_Launching(object sender, LaunchingEventArgs e)
        {
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();

            // 저번에 에러가 발생했으면 ErrorFilePath에 해당 에러 정보가 저장된다.
            if (storage.FileExists(ErrorSavePath))
            {
                // 있으면 열어서
                using (StreamReader ErrorReader = new StreamReader(storage.OpenFile(ErrorSavePath, FileMode.Open)))
                {
                    // 에러 정보 전송 관련 메시지를 띄우고 (보내면 : OK 안보내면 : Cancel)
                    MessageBoxResult mbr = MessageBox.Show("지난 애플리케이션 실행 때 예기치 못한 오류로 애플리케이션이 종료되었습니다. 오류 내용을 개발자에게 이메일로 보내시겠습니까? 이메일을 보내 주시면 문제 해결에 큰 도움이 됩니다.", "문제 해결", MessageBoxButton.OKCancel);
                    
                    // 보낸다고 응답하면
                    if (mbr == MessageBoxResult.OK)
                    {
                        // 이메일 보내는 Task를 열어서 보낸다.
                        EmailComposeTask ErrorEmailTask = new EmailComposeTask
                        {
                            To = "raon_support@naver.com",
                            Subject = "[오늘의 유머] 예기치 못한 오류 정보를 전송합니다.",
                            Body = "다음과 같은 오류가 발생하여 이메일을 보냅니다. \n\n" + ErrorReader.ReadToEnd()
                        };

                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            ErrorEmailTask.Show();
                        });
                    }
                }
                // 다음 번에 또 나타나는 것을 방지하기 위해서 에러 정보 파일을 지운다.
                storage.DeleteFile(ErrorSavePath);
            }
        }

        private void Application_Activated(object sender, ActivatedEventArgs e)
        {
        }

        // 응용 프로그램이 비활성화(백그라운드로 전송)될 때 실행할 코드입니다.
        // 이 코드는 응용 프로그램이 닫힐 때는 실행되지 않습니다.
        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
            // 여기서 필수 응용 프로그램 상태가 유지되는지 확인합니다.
        }

        // 응용 프로그램이 닫힐 때(예: 사용자가 [뒤로]를 누르는 경우) 실행할 코드입니다.
        // 이 코드는 응용 프로그램이 비활성화될 때는 실행되지 않습니다.
        private void Application_Closing(object sender, ClosingEventArgs e)
        {
        }

        // 탐색이 실패할 때 실행할 코드입니다.
        private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // 탐색이 실패했습니다. 중단하고 디버거를 실행합니다.
                System.Diagnostics.Debugger.Break();
            }
        }

        // 처리되지 않은 예외에 대해 실행할 코드입니다.
        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs args)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // 처리되지 않은 예외가 발생했습니다. 중단하고 디버거를 실행합니다.
                System.Diagnostics.Debugger.Break();
            }

            // 에러가 발생하면 
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();

            // ErrorSavePath에 파일을 만들어서 다음 실행 때 오류 메시지를 띄울 수 있게 한다.
            using (StreamWriter ErrorWriter = new StreamWriter(storage.OpenFile(ErrorSavePath, FileMode.Create)))
            {
                // 에러의 타입을 기록하고
                ErrorWriter.WriteLine(args.ExceptionObject.GetType().ToString() + "\n");

                // 에러 세부 내용을 기록하고
                ErrorWriter.Write(args.ExceptionObject.ToString() + "\n");

                // 어디에서 발생했는지 기록한다.
                if (args.ExceptionObject.InnerException != null)
                {
                    ErrorWriter.WriteLine(args.ExceptionObject.InnerException.ToString());
                }
            }
        }

        #region 전화 응용 프로그램 초기화

        // 이중 초기화를 사용하지 않습니다.
        private bool phoneApplicationInitialized = false;

        // 이 메서드에 추가 코드를 추가하지 않습니다.
        private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            // 프레임을 만들지만 프레임을 아직 RootVisual로 설정하지 않습니다. 이렇게 하면
            // 응용 프로그램이 렌더링할 준비가 될 때까지 시작 화면이 활성 상태를 유지합니다.
            RootFrame = new TransitionFrame();
            RootFrame.Navigated += CompleteInitializePhoneApplication;

            // 탐색 오류를 처리합니다.
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            // 다시 초기화하지 않습니다.
            phoneApplicationInitialized = true;
        }

        // 이 메서드에 추가 코드를 추가하지 않습니다.
        private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
        {
            // 응용 프로그램을 렌더링하도록 루트 Visual을 설정합니다.
            if (RootVisual != RootFrame)
                RootVisual = RootFrame;

            // 더 이상 필요하지 않으므로 이 처리기를 제거합니다.
            RootFrame.Navigated -= CompleteInitializePhoneApplication;
        }

        #endregion
    }
}